
export class ServiceError extends Error {}

export class Service {
  showError (err: Error) {
    throw new ServiceError(err.message)
  }
}

export function injectable<T extends { new (..._args: Any[]): {} }> (Ctor: T) {
  let instance!: Any
  return new Proxy(Ctor, {
    construct (t, args) {
      if (!instance) {
        instance = new Ctor(args)
      }
      return instance
    }
  })
}

const runnerMap: { [key: string]: ((_res: Any) => void)[] | undefined } = {}
/**
 * 互斥注解
 * 用于保证某个方法同一时间只有单次调用
 */
export function mutex (target: Any, property: string) {
  const oriFn = target[property]
  const key = `${target.constructor.name}-${property}`
  Object.defineProperty(target, property, {
    value: async function (...args: Any[]) {
      if (runnerMap[key]) {
        return await new Promise(res => {
          runnerMap[key]?.push((result: Any) => res(result))
        })
      } else {
        runnerMap[key] = []
      }
      const res = await Reflect.apply(oriFn, this, args || [])
      runnerMap[key]?.forEach(fn => fn(res))
      runnerMap[key] = undefined
      return res
    }
  })
  return target[property]
}
